package com.neusoft.bizcore.auth.common.jwt;

import java.time.Instant;
import java.util.Date;
import java.util.List;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.impl.TextCodec;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class JwtAuthProvider {

    private final long expiration;
    private final String signingKey;

    public JwtAuthProvider(final long expiration, final String signingKey) {
        this.expiration = expiration;
        this.signingKey = TextCodec.BASE64.encode(signingKey);
    }

    public String generateToken(final String username, List<String> roles) {
        final Claims claims = Jwts.claims();
        claims.setAudience(username);
        claims.put("roles", roles);
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(new Date(Instant.now().toEpochMilli() + this.expiration))
                .signWith(SignatureAlgorithm.HS512, this.signingKey)
                .compact();
    }

    public String parseUsername(final String token) {
        return Jwts.parser()
                .setSigningKey(this.signingKey)
                .parseClaimsJws(token)
                .getBody().getAudience();
    }

    @SuppressWarnings("unchecked")
    public List<String> parseRoles(final String token) {
        final Object v = Jwts.parser()
                .setSigningKey(this.signingKey)
                .parseClaimsJws(token)
                .getBody().get("roles");
        if (v instanceof List) {
            return (List<String>) v;
        } else {
            return null;
        }

    }

    public boolean validate(final String token) {
        try {
            Jwts.parser().setSigningKey(this.signingKey).parseClaimsJws(token);
            return true;
        } catch (final SignatureException e) {
            JwtAuthProvider.log.warn("Invalid JWT signature -> Message: {} ", e.getMessage());
        } catch (final MalformedJwtException e) {
            JwtAuthProvider.log.warn("Invalid JWT token -> Message: {}", e.getMessage());
        } catch (final ExpiredJwtException e) {
            JwtAuthProvider.log.warn("Expired JWT token -> Message: {}", e.getMessage());
        } catch (final UnsupportedJwtException e) {
            JwtAuthProvider.log.warn("Unsupported JWT token -> Message: {}", e.getMessage());
        } catch (final IllegalArgumentException e) {
            JwtAuthProvider.log.warn("JWT claims string is empty -> Message: {}", e.getMessage());
        }

        return false;
    }
}
